#pragma once

#include "GLSLShader.h"
#include "../math/counted_ptr.h"

namespace PBVP {
	/// A class encapsulate GLSL program
	/** 
	 * This class contains the shaders of the program
	 */
	class GLSLProgram
	{
	public:
		/// Constructor
		GLSLProgram(GLSLShader *vertShader, GLSLShader *fragmentShader);
		/// 
		GLSLProgram(const QString &vertFname, const QString &fragFname);
		/// Copy constructor
		GLSLProgram(const GLSLProgram& program);

		/// Destructor
		virtual ~GLSLProgram(void);

		/// 
		bool isValid() const {
			return m_isValid;
		}
		/// 
		GLuint programId() const {
			return m_programId;
		}

		// Convenient functions to set uniform variables
		void setUniform1f(const char* varname, GLfloat v0);
		void setUniform2f(const char* varname, GLfloat v0, GLfloat v1);
		void setUniform3f(const char* varname, GLfloat v0, GLfloat v1, GLfloat v2);
		void setUniform4f(const char* varname, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);  

		void setUniform1i(const char* varname, GLint v0);
		void setUniform2i(const char* varname, GLint v0, GLint v1);
		void setUniform3i(const char* varname, GLint v0, GLint v1, GLint v2);
		void setUniform4i(const char* varname, GLint v0, GLint v1, GLint v2, GLint v3);

		void setUniform1fv(const char* varname, GLsizei count, GLfloat *value);
		void setUniform2fv(const char* varname, GLsizei count, GLfloat *value);
		void setUniform3fv(const char* varname, GLsizei count, GLfloat *value);
		void setUniform4fv(const char* varname, GLsizei count, GLfloat *value);
		void setUniform1iv(const char* varname, GLsizei count, GLint *value);
		void setUniform2iv(const char* varname, GLsizei count, GLint *value);
		void setUniform3iv(const char* varname, GLsizei count, GLint *value);
		void setUniform4iv(const char* varname, GLsizei count, GLint *value);

		void setUniformMatrix2fv(const char* varname, GLsizei count, GLboolean transpose, GLfloat *value);
		void setUniformMatrix3fv(const char* varname, GLsizei count, GLboolean transpose, GLfloat *value);
		void setUniformMatrix4fv(const char* varname, GLsizei count, GLboolean transpose, GLfloat *value);

		void setVertexAttrib1f(GLuint index, GLfloat v0);
		void setVertexAttrib2f(GLuint index, GLfloat v0, GLfloat v1);
		void setVertexAttrib3f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2);
		void setVertexAttrib4f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);

	private:
		void init();

		GLuint m_programId;
		bool m_isValid;
		counted_ptr<GLSLShader> m_vertShader;
		counted_ptr<GLSLShader> m_fragShader;

		GLint getUniformLocation(const char* name);
	};
}
